using System.Collections.Generic;
using data.contracts;



using System;

namespace modelbuilder.parser.pins {



public class Parser {
	public const int _EOF = 0;
	public const int _ident = 1;
	public const int _dot = 2;
	public const int maxT = 11;

	const bool T = true;
	const bool x = false;
	const int minErrDist = 2;
	
	public Scanner scanner;
	public Errors  errors;

	public Token t;    // last recognized token
	public Token la;   // lookahead token
	int errDist = minErrDist;

public IList<Pin> _pins = new List<Pin>();

  bool IsNamespace() {
	Token next = la;
	Token nextNext = scanner.Peek();
	Token nextNextNext = scanner.Peek();

	return next.kind == _dot && nextNext.kind == _ident && nextNextNext.kind == _dot;
  }



	public Parser(Scanner scanner) {
		this.scanner = scanner;
		errors = new Errors();
	}

	void SynErr (int n) {
		if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n);
		errDist = 0;
	}

	public void SemErr (string msg) {
		if (errDist >= minErrDist) errors.SemErr(t.line, t.col, msg);
		errDist = 0;
	}
	
	void Get () {
		for (;;) {
			t = la;
			la = scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }

			la = t;
		}
	}
	
	void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}
	
	bool StartOf (int s) {
		return set[s, la.kind];
	}
	
	void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}


	bool WeakSeparator(int n, int syFol, int repFol) {
		int kind = la.kind;
		if (kind == n) {Get(); return true;}
		else if (StartOf(repFol)) {return false;}
		else {
			SynErr(n);
			while (!(set[syFol, kind] || set[repFol, kind] || set[0, kind])) {
				Get();
				kind = la.kind;
			}
			return StartOf(syFol);
		}
	}

	
	void Ebc() {
		pins();
	}

	void pins() {
		Pin _pin; 
		typedQualifiedPin(out _pin);
		_pins.Add(_pin); 
		while (la.kind == 3) {
			Get();
			typedQualifiedPin(out _pin);
			_pins.Add(_pin); 
		}
	}

	void typedQualifiedPin(out Pin _pin) {
		string _type = ""; 
		if (la.kind == 4) {
			Get();
			type(out _type);
			Expect(5);
		}
		qualifiedPin(out _pin);
		_pin.Type = _type; 
	}

	void type(out string _type) {
		Expect(1);
		_type = t.val; string _generictype = ""; 
		while (la.kind == 2) {
			Get();
			Expect(1);
			_type = _type + "." + t.val; 
		}
		if (la.kind == 6) {
			Get();
			type(out _generictype);
			_type = _type + "<" + _generictype; 
			while (la.kind == 3) {
				Get();
				type(out _generictype);
				_type = _type + "," + _generictype; 
			}
			Expect(7);
			_type = _type + ">"; 
		}
		if (la.kind == 8) {
			Get();
			_type = _type + "["; 
			while (la.kind == 3) {
				Get();
				_type = _type + ","; 
			}
			Expect(9);
			_type = _type + "]"; 
		}
		while (la.kind == 10) {
			Get();
			_type = _type + "*"; 
		}
	}

	void qualifiedPin(out Pin _pin) {
		Expect(1);
		_pin = new Pin { Board = t.val, Name = "", Type = "" }; 
		while (IsNamespace()) {
			Expect(2);
			Expect(1);
			_pin.Board = _pin.Board + "." + t.val; 
		}
		if (la.kind == 2) {
			Get();
			Expect(1);
			_pin.Name = t.val; 
		}
	}



	public void Parse() {
		la = new Token();
		la.val = "";		
		Get();
		Ebc();
		Expect(0);

	}
	
	static readonly bool[,] set = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x}

	};
} // end Parser


public class Errors {
	public int count = 0;                                    // number of errors detected
	public System.IO.TextWriter errorStream = Console.Out;   // error messages go to this stream
	public string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text

	public virtual void SynErr (int line, int col, int n) {
		string s;
		switch (n) {
			case 0: s = "EOF expected"; break;
			case 1: s = "ident expected"; break;
			case 2: s = "dot expected"; break;
			case 3: s = "\",\" expected"; break;
			case 4: s = "\"(\" expected"; break;
			case 5: s = "\")\" expected"; break;
			case 6: s = "\"<\" expected"; break;
			case 7: s = "\">\" expected"; break;
			case 8: s = "\"[\" expected"; break;
			case 9: s = "\"]\" expected"; break;
			case 10: s = "\"*\" expected"; break;
			case 11: s = "??? expected"; break;

			default: s = "error " + n; break;
		}
		errorStream.WriteLine(errMsgFormat, line, col, s);
		count++;
	}

	public virtual void SemErr (int line, int col, string s) {
		errorStream.WriteLine(errMsgFormat, line, col, s);
		count++;
	}
	
	public virtual void SemErr (string s) {
		errorStream.WriteLine(s);
		count++;
	}
	
	public virtual void Warning (int line, int col, string s) {
		errorStream.WriteLine(errMsgFormat, line, col, s);
	}
	
	public virtual void Warning(string s) {
		errorStream.WriteLine(s);
	}
} // Errors


public class FatalError: Exception {
	public FatalError(string m): base(m) {}
}
}